#pragma once

#include <queue>
#include <vector>
#include <mutex>
#include <thread>
#include <future>
#include <functional>
#include <condition_variable>

#include "Task.h"

class ThreadPool {
private:
    std::vector<std::thread> threads;   // 线程池中的线程
    std::queue<Task> tasks;             // 任务队列
    std::mutex queue_mutex;             // 任务队列的互斥量
    std::condition_variable condition;  // 任务队列的条件变量
    bool stop;                          // 线程池是否被停止

public:
    // 构造函数，接收线程池中的线程数目
    explicit ThreadPool(size_t num_threads);

    // 停止线程池
    ~ThreadPool();

    ThreadPool(const ThreadPool &) = delete;

    ThreadPool(ThreadPool &&) = delete;

    ThreadPool &operator=(const ThreadPool &) = delete;

    ThreadPool &operator=(ThreadPool &&) = delete;

    // 模板分离编译问题，写在头文件里
    // 添加任务到线程池
    template<typename Func, typename... Args>
    void enqueue(Func &&func, Args &&... args) {
        {
            // 使用unique_lock进行线程同步
            std::unique_lock<std::mutex> lock(queue_mutex);

            // 如果线程池已被停止，则抛出异常
            if (stop) {
                throw std::runtime_error("enqueue on stopped ThreadPool");
            }

            // 将任务添加到任务队列
            tasks.emplace(Task(std::forward<Func>(func), std::forward<Args>(args)...));
        }

        // 通知一个等待中的线程有新的任务可用
        condition.notify_one();
    }
};

